#include "gb28181_message.h"
#include "../gb28181_service.h"
#include "gb28181_catalog.h"
#include "gb28181_ptz.h"
#include "gb28181_record.h"
#include "../gb28181_utils.h"
#include "utils_log.h"
#include <sstream>
#include <cstring>

namespace El {
namespace GB28181 {

void GB28181Message::ProcessMessageRequest(
    eXosip_event_t *event,
    eXosip_t *exosip_context,
    const SipServerConfig &config,
    std::function<void(const std::string &)> responseCallback,
    std::function<bool(const PTZControlInfo &)> ptzCallback,
    std::function<std::vector<RecordInfo>(const RecordQueryInfo &)> recordCallback)
{
    if (!event || !event->request || !exosip_context) {
        EL_ERROR("Invalid parameters in ProcessMessageRequest");
        return;
    }

    osip_message_t *request = event->request;
    EL_DEBUG("Processing message request for device {}", config.device_id);

    if (MSG_IS_MESSAGE(request) && IsMANSCDPMessage(request)) {
        std::string xml_content = ExtractXmlBody(request);

        if (!xml_content.empty()) {
            MessageType msg_type = ParseMessageType(xml_content);
            EL_DEBUG("Parsed message type: {}", static_cast<int>(msg_type));

            switch (msg_type) {
                case MessageType::DEVICE_INFO: {
                    EL_INFO("Processing DeviceInfo query for device {}", config.device_id);
                    std::string sn = GB28181Utils::GenerateSN();
                    std::string response_xml = GB28181Catalog::CreateDeviceInfoXml(config, sn);
                    SendResponse(exosip_context, event, 200, response_xml);
                    if (responseCallback) {
                        responseCallback("Responded to DeviceInfo query");
                    }
                    break;
                }

                case MessageType::CATALOG: {
                    EL_INFO("Processing Catalog query for device {}", config.device_id);
                    std::string sn = GB28181Utils::GenerateSN();
                    std::string response_xml = GB28181Catalog::CreateCatalogXml(config, sn);
                    SendResponse(exosip_context, event, 200, response_xml);
                    if (responseCallback) {
                        responseCallback("Responded to Catalog query");
                    }
                    break;
                }

                case MessageType::DEVICE_CONTROL: {
                    EL_INFO("Processing DeviceControl message for device {}", config.device_id);
                    // Use PTZ handler for device control
                    GB28181PTZ::ProcessDeviceControl(event, exosip_context, config, ptzCallback);
                    if (responseCallback) {
                        responseCallback("Processed DeviceControl message");
                    }
                    break;
                }

                case MessageType::RECORD_INFO: {
                    EL_INFO("Processing RecordInfo query for device {}", config.device_id);
                    // Use record handler for record query
                    GB28181Record::ProcessRecordQuery(event, exosip_context, config, recordCallback);
                    if (responseCallback) {
                        responseCallback("Processed RecordInfo query");
                    }
                    break;
                }

                default:
                    EL_DEBUG("Unknown message type, sending OK response");
                    SendResponse(exosip_context, event, 200);
                    break;
            }
        } else {
            EL_DEBUG("Empty XML content, sending OK response");
            SendResponse(exosip_context, event, 200);
        }
    } else {
        EL_DEBUG("Non-MANSCDP message, ignoring");
    }
}

void GB28181Message::SendHeartbeat(eXosip_t *exosip_context, const SipServerConfig &config)
{
    if (!exosip_context) {
        EL_ERROR("Invalid exosip_context in SendHeartbeat");
        return;
    }

    EL_DEBUG("Sending heartbeat for device {}", config.device_id);

    std::string from = "sip:" + config.device_id + "@" + config.domain;
    std::string to = "sip:" + config.server_id + "@" + config.domain;
    std::string sn = GB28181Utils::GenerateSN();
    std::string heartbeat_xml = CreateHeartbeatXml(config.device_id, sn);

    eXosip_lock(exosip_context);
    osip_message_t *message = BuildMessageRequest(exosip_context, from, to, heartbeat_xml);
    if (message) {
        eXosip_message_send_request(exosip_context, message);
    }
    eXosip_unlock(exosip_context);
}

void GB28181Message::SendResponse(eXosip_t *exosip_context,
                                  eXosip_event_t *event,
                                  int status_code,
                                  const std::string &content)
{
    if (!exosip_context || !event)
        return;

    osip_message_t *response = nullptr;
    eXosip_message_build_answer(exosip_context, event->tid, status_code, &response);

    if (response) {
        if (!content.empty()) {
            osip_message_set_content_type(response, "Application/MANSCDP+xml");
            osip_message_set_body(response, content.c_str(), content.length());
        }
        eXosip_message_send_answer(exosip_context, event->tid, status_code, response);
    }
}

std::string GB28181Message::CreateHeartbeatXml(const std::string &device_id, const std::string &sn)
{
    std::stringstream xml;
    xml << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
        << "<Notify>\n"
        << "<CmdType>Keepalive</CmdType>\n"
        << "<SN>" << sn << "</SN>\n"
        << "<DeviceID>" << device_id << "</DeviceID>\n"
        << "<Status>OK</Status>\n"
        << "<Info>\n"
        << "<DeviceID>" << device_id << "</DeviceID>\n"
        << "</Info>\n"
        << "</Notify>\n";

    return xml.str();
}

std::string GB28181Message::CreateAlarmXml(const std::string &device_id,
                                           const std::string &sn,
                                           int alarm_priority,
                                           int alarm_method,
                                           const std::string &alarm_time,
                                           const std::string &alarm_description)
{
    std::stringstream xml;
    xml << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
        << "<Notify>\n"
        << "<CmdType>Alarm</CmdType>\n"
        << "<SN>" << sn << "</SN>\n"
        << "<DeviceID>" << device_id << "</DeviceID>\n"
        << "<AlarmPriority>" << alarm_priority << "</AlarmPriority>\n"
        << "<AlarmMethod>" << alarm_method << "</AlarmMethod>\n"
        << "<AlarmTime>" << alarm_time << "</AlarmTime>\n"
        << "<AlarmDescription>" << alarm_description << "</AlarmDescription>\n"
        << "</Notify>\n";

    return xml.str();
}

GB28181Message::MessageType GB28181Message::ParseMessageType(const std::string &xml)
{
    if (xml.find("<CmdType>DeviceInfo</CmdType>") != std::string::npos) {
        return MessageType::DEVICE_INFO;
    } else if (xml.find("<CmdType>Catalog</CmdType>") != std::string::npos) {
        return MessageType::CATALOG;
    } else if (xml.find("<CmdType>Keepalive</CmdType>") != std::string::npos) {
        return MessageType::KEEPALIVE;
    } else if (xml.find("<CmdType>DeviceStatus</CmdType>") != std::string::npos) {
        return MessageType::DEVICE_STATUS;
    } else if (xml.find("<CmdType>RecordInfo</CmdType>") != std::string::npos) {
        return MessageType::RECORD_INFO;
    } else if (xml.find("<CmdType>Alarm</CmdType>") != std::string::npos) {
        return MessageType::ALARM;
    } else if (xml.find("<CmdType>ConfigDownload</CmdType>") != std::string::npos) {
        return MessageType::CONFIG_DOWNLOAD;
    } else if (xml.find("<CmdType>PresetQuery</CmdType>") != std::string::npos) {
        return MessageType::PRESET_QUERY;
    } else if (xml.find("<CmdType>DeviceControl</CmdType>") != std::string::npos) {
        return MessageType::DEVICE_CONTROL;
    }

    return MessageType::UNKNOWN;
}

bool GB28181Message::IsMANSCDPMessage(osip_message_t *message)
{
    if (!message)
        return false;

    osip_content_type_t *content_type = osip_message_get_content_type(message);
    return (content_type && content_type->type && content_type->subtype &&
            strcmp(content_type->type, "Application") == 0 && strcmp(content_type->subtype, "MANSCDP+xml") == 0);
}

std::string GB28181Message::ExtractXmlBody(osip_message_t *message)
{
    if (!message)
        return "";

    osip_body_t *body = nullptr;
    osip_message_get_body(message, 0, &body);

    if (body && body->body) {
        return std::string(body->body);
    }

    return "";
}

osip_message_t *GB28181Message::BuildMessageRequest(eXosip_t *exosip_context,
                                                    const std::string &from,
                                                    const std::string &to,
                                                    const std::string &xml_content)
{
    if (!exosip_context)
        return nullptr;

    osip_message_t *message = nullptr;
    eXosip_message_build_request(exosip_context, &message, "MESSAGE", to.c_str(), from.c_str(), nullptr);

    if (message) {
        osip_message_set_content_type(message, "Application/MANSCDP+xml");
        osip_message_set_body(message, xml_content.c_str(), xml_content.length());
    }

    return message;
}

} // namespace GB28181
} // namespace El
